package com.sl.water.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sl.water.dto.ForecastSchemeDTO;
import com.sl.water.entity.*;
import com.sl.water.service.*;
import com.sl.water.vo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;

import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @description:
 * @author: duan
 * @time: 2025-05-26 17:29
 */
@Service
@RequiredArgsConstructor
public class RiskWarnServiceImpl implements RiskWarnService {

    private final JdbcTemplate jdbcTemplate;
    private final StReservoirFloodLimitWaterLevelBService stReservoirFloodLimitWaterLevelBService;
    private final BThresholdWaterService bThresholdWaterService;
    private final ForecastSchemeService forecastSchemeService;
    private final RehearsalSchemeService rehearsalSchemeService;
    private final BRInfoService brInfoService;
    private final BRCompanyService brCompanyService;

    @Override
    public ReservoirLimitWarnVO queryReservoirWarn() {
        LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
        String nowDate = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_FORMATTER);
        String sql = "SELECT * FROM st_r_rsvr WHERE stcd=(SELECT station_code FROM st_station_b WHERE station_name='赵庄水库水位站') " +
                "AND tm<='" + nowDate + "' ORDER BY tm desc LIMIT 1";
        ReservoirLimitWarnVO reservoirLimitWarnVO = new ReservoirLimitWarnVO();
        List<Map<String, Object>> maps = this.jdbcTemplate.queryForList(sql);
        if (!maps.isEmpty()) {
            Map<String, Object> reservoirMap = maps.get(0);
            Double z = Double.parseDouble(reservoirMap.get("rz").toString());
            reservoirLimitWarnVO.setZ(z);
            Double floodLimitWaterLevel = getFloodLimitWaterLevel();
            reservoirLimitWarnVO.setZLimit(floodLimitWaterLevel);
            BigDecimal dis = BigDecimal.valueOf(floodLimitWaterLevel).subtract(BigDecimal.valueOf(z));
            reservoirLimitWarnVO.setZDis(dis.doubleValue());
            reservoirLimitWarnVO.setTm((LocalDateTime) reservoirMap.get("tm"));
        }
        return reservoirLimitWarnVO;
    }

    @Override
    public RiverLimitWarnVO queryRiverWarn(String stcd) {
        RiverLimitWarnVO riverLimitWarnVO = new RiverLimitWarnVO();
        String sql = "SELECT station_name FROM st_station_b WHERE station_code ='" + stcd + "'";
        List<Map<String, Object>> maps = this.jdbcTemplate.queryForList(sql);
        if (!maps.isEmpty()) {
            Map<String, Object> station = maps.get(0);
            riverLimitWarnVO.setName(station.get("station_name").toString());
        }
        LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
        String nowDate = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_FORMATTER);
        String riverSql = "SELECT * FROM st_r_river WHERE stcd='" + stcd + "'AND tm<='" + nowDate + "' ORDER BY tm desc LIMIT 1";
        List<Map<String, Object>> rivers = this.jdbcTemplate.queryForList(riverSql);
        if (!rivers.isEmpty()) {
            Map<String, Object> riverMap = rivers.get(0);
            BigDecimal z = (BigDecimal) riverMap.get("z");
            Double threshold = getThreshold();
            riverLimitWarnVO.setZ(z);
            riverLimitWarnVO.setQ((BigDecimal) riverMap.get("q"));
            riverLimitWarnVO.setZLimit(BigDecimal.valueOf(threshold));
            riverLimitWarnVO.setZDis(BigDecimal.valueOf(threshold).subtract(z));
        }
        Double threshold = getThreshold();
        riverLimitWarnVO.setZLimit(BigDecimal.valueOf(threshold));
        return riverLimitWarnVO;
    }

    @Override
    public MydWarnVO queryOverflowWarn() {
        MydWarnVO mydWarnVO = new MydWarnVO();
        String sql = "SELECT * FROM st_station_b WHERE station_name !='赵庄水库水位站'";
        List<Map<String, Object>> stationList = this.jdbcTemplate.queryForList(sql);
        List<StationVO> overflowArr = new ArrayList<>();
        LocalDateTime localDateTime = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
        String nowDate = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_FORMATTER);
        int num = 0;
        for (Map<String, Object> stationMap : stationList) {
            String stationCode = stationMap.get("station_code").toString();
            String riverSql = "SELECT * FROM st_r_river WHERE stcd='" + stationCode + "'AND tm<='" + nowDate + "' ORDER BY tm desc LIMIT 1";
            List<Map<String, Object>> riverList = this.jdbcTemplate.queryForList(riverSql);
            if (!riverList.isEmpty()) {
                Map<String, Object> riverMap = riverList.get(0);

                BigDecimal z = BigDecimal.valueOf(Double.parseDouble(riverMap.get("z").toString()));
                //对比【st_rvfcch_b】中的【ldkel左堤高程】【rdkel右堤高程】中的最小值，大于就属于漫溢点
                String rvfcchSql = "SELECT * FROM st_rvfcch_b WHERE (ldkel<'" + z + "' or rdkel<'" + z + "') AND stcd='" + stationCode + "'";
                List<Map<String, Object>> rvfcchList = jdbcTemplate.queryForList(rvfcchSql);
                if (rvfcchList.size() > 0) {
                    num++;
                    StationVO stationVO = new StationVO();
                    stationVO.setName(String.valueOf(stationMap.get("station_name")));
                    stationVO.setLon(stationMap.get("lon") != null ? (BigDecimal) stationMap.get("lon") : BigDecimal.ZERO);
                    stationVO.setLat(stationMap.get("lat") != null ? (BigDecimal) stationMap.get("lat") : BigDecimal.ZERO);
                    overflowArr.add(stationVO);
                }
            }
        }
        mydWarnVO.setNum(num).setList(overflowArr);

        return mydWarnVO;
    }

    @Override
    public YbWarnVO queryForecastWarn() {
        YbWarnVO ybWarnVO = new YbWarnVO();
        ybWarnVO.setRsvr(getRsvr());
        ybWarnVO.setRiver(getRiver());
        ybWarnVO.setWh(getWh());
        return ybWarnVO;
    }

    /**
     * 生成水库预报预警
     *
     * @return 水库预报预警
     */
    private YbWarnVO.Rsvr getRsvr() {
        YbWarnVO.Rsvr rsvr = new YbWarnVO.Rsvr();
        //预测水位
        ForecastSchemeDTO forecastSchemeDTO = forecastSchemeService.getForecastSchemeDTO();
        Double z = forecastSchemeDTO.getReservoirMaxWaterLevelOrDefault();
        //汛限水位
        Double zLimit = getFloodLimitWaterLevel();
        //距汛限水位
        BigDecimal zYb = BigDecimal.valueOf(zLimit).subtract(BigDecimal.valueOf(z));
        //警戒时间(第一次超出汛限水位对应的时间节点)
        List<Double> waterLevelProcess = forecastSchemeDTO.getReservoirWaterLevelProcess();
        List<String> timeSeries = forecastSchemeDTO.getReservoirTimeSeries();
        String tm = getTm(zLimit, waterLevelProcess, timeSeries);
        rsvr.setZ(z);
        rsvr.setZLimit(zLimit);
        rsvr.setZYb(zYb.doubleValue());
        rsvr.setTm(tm);
        return rsvr;
    }

    /**
     * 生成河道预报预警
     *
     * @return 河道预报预警
     */
    private YbWarnVO.River getRiver() {
        YbWarnVO.River river = new YbWarnVO.River();
        //预测水位
        ForecastSchemeDTO forecastSchemeDTO = forecastSchemeService.getForecastSchemeDTO();
        Double z = forecastSchemeDTO.getRiverSectionAnalysisDTOMaxWaterLevel();
        //汛限水位
        Double zLimit = getThreshold();
        //距汛限水位
        BigDecimal zYb = BigDecimal.valueOf(zLimit).subtract(BigDecimal.valueOf(z));
        //警戒时间(第一次超出汛限水位对应的时间节点)
        List<Double> waterLevelProcess = forecastSchemeDTO.getRiverSectionAnalysisDTOWaterLevelProcess();
        List<String> timeSeries = forecastSchemeDTO.getRiverSectionAnalysisDTOTmProcess();
        String tm = getTm(zLimit, waterLevelProcess, timeSeries);
        river.setZ(z);
        river.setZLimit(zLimit);
        river.setZYb(zYb.doubleValue());
        river.setTm(tm);
        return river;
    }

    private YbWarnVO.Wh getWh() {
        YbWarnVO.Wh wh = new YbWarnVO.Wh();
        int person = 0, num = 0;
        double mj = 0.0;
        JSONArray cmpList = new JSONArray();
        ForecastSchemeDTO forecastSchemeDTO = forecastSchemeService.getForecastSchemeDTO();
        //预报方案ID
        Long id = forecastSchemeDTO.getId();
        //根据预报方案ID查询预演方案ID
        RehearsalScheme rehearsalScheme = rehearsalSchemeService.
                getOne(new LambdaQueryWrapper<RehearsalScheme>()
                        .eq(RehearsalScheme::getForecastId, id));
        if (Objects.nonNull(rehearsalScheme)) {
            Long rehearsalSchemeId = rehearsalScheme.getId();
            List<BRInfo> infoList = brInfoService
                    .list(new LambdaQueryWrapper<BRInfo>()
                            .eq(BRInfo::getSId, rehearsalSchemeId));
            mj = infoList.stream().mapToDouble(BRInfo::getArea).max().orElse(0.0);
            List<BRCompany> companyList = brCompanyService
                    .list(new LambdaQueryWrapper<BRCompany>()
                            .eq(BRCompany::getSId, rehearsalSchemeId)
                            .ge(BRCompany::getDepth, 0.2));
            //去重
            List<BRCompany> distinctCompanies = companyList.stream()
                    .collect(Collectors.toMap(
                            BRCompany::getName,
                            p -> p,
                            (p1, p2) -> p1
                    ))
                    .values()
                    .stream()
                    .collect(Collectors.toList());
            for (BRCompany brCompany : distinctCompanies) {
                String name = brCompany.getName();
                String sql = "SELECT * FROM b_e_yld WHERE NAME='" + name + "'";
                List<Map<String, Object>> beYldList = jdbcTemplate.queryForList(sql);
                cmpList = JSONUtil.parseArray(beYldList);
                num = beYldList.size();
            }
        }
        wh.setList(cmpList);
        wh.setNum(num);
        wh.setMj(mj);
        wh.setPerson(person);
        return wh;
    }

    private String getTm(Double zLimit, List<Double> waterLevelProcess, List<String> timeSeries) {
        String tm = "";
        int firtsGreaterIndex = IntStream.range(0, waterLevelProcess.size())
                .filter(i -> waterLevelProcess.get(i) > zLimit)
                .findFirst()
                .orElse(-1);
        if (firtsGreaterIndex != -1) {
            tm = timeSeries.get(firtsGreaterIndex);
        }
        return tm;
    }

    private Double getFloodLimitWaterLevel() {
        Double floodLimitWaterLevel = 0.0;
        List<StReservoirFloodLimitWaterLevelB> stReservoirFloodLimitWaterLevelBList = stReservoirFloodLimitWaterLevelBService
                .list(new LambdaQueryWrapper<StReservoirFloodLimitWaterLevelB>()
                        .orderByDesc(StReservoirFloodLimitWaterLevelB::getUpdateTime));
        if (stReservoirFloodLimitWaterLevelBList.size() > 0) {
            floodLimitWaterLevel = stReservoirFloodLimitWaterLevelBList.get(0).getFloodLimitWaterLevel();
        }
        return floodLimitWaterLevel;
    }

    private Double getThreshold() {
        Double threshold = 0.0;
        BThresholdWater bThresholdWater = bThresholdWaterService
                .list(new LambdaQueryWrapper<BThresholdWater>()
                        .eq(BThresholdWater::getKind, "河道水位")
                        .orderByDesc(BThresholdWater::getLevel))
                .stream().max(Comparator.comparingInt(BThresholdWater::getLevel)).orElse(null);
        if (bThresholdWater != null) {
            threshold = bThresholdWater.getThreshold();
        }
        return threshold;
    }
}



